package net.sunofbeaches.services.impl;

import lombok.extern.slf4j.Slf4j;
import net.sunofbeaches.dao.ImagesDao;
import net.sunofbeaches.pojo.Images;
import net.sunofbeaches.pojo.SobUser;
import net.sunofbeaches.response.ResponseResult;
import net.sunofbeaches.services.IUserService;
import net.sunofbeaches.services.ImageService;
import net.sunofbeaches.utils.Constants;
import net.sunofbeaches.utils.IdWorker;
import net.sunofbeaches.utils.TextUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.Transactional;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;

@Slf4j
@Service
@Transactional
public class ImageServiceImpl extends BaseService implements ImageService {

    public static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy_MM_dd");
    // 上传路径
    @Value("${sob.blog.image.save-path}")
    public String imagePath;
    @Value("${sob.blog.image.max-size}")
    public long maxSize;
    @Autowired
    private IdWorker idWorker;
    @Autowired
    private IUserService iUserService;
    @Autowired
    private ImagesDao imagesDao;

    /**
     * 上传照片
     *
     * @param file
     * @return
     */
    @Override
    public ResponseResult uploadImage(MultipartFile file) {
        // 判断是否有文件
        if (file == null) {
            return ResponseResult.FAILED("图片不可以为空.");
        }
        String contentType = file.getContentType();
        log.info("contentType == > " + contentType);
        if (TextUtils.isEmpty(contentType)) {
            return ResponseResult.FAILED("图片格式错误.");
        }
        // 判断文件类型，我们只支持图片上传，比如说:png，jpg, gif
        // 获取相关数据，比如说文件类型，文件名称
        String name = file.getName();
        String originalFilename = file.getOriginalFilename();
        log.info("name == > " + name);
        log.info("originalFilename == > " + originalFilename);
        String type = null;
        type = getString(contentType, originalFilename);
        if (type == null) {
            return ResponseResult.FAILED("不支持此图片类型");
        }

        long size = file.getSize();
        // 限制文件的大小
        log.info("maxSize == > " + maxSize + "  size == > " + size);
        if (size > maxSize) {
            return ResponseResult.FAILED("图片最大支持" + (maxSize / 1024 / 1024) + "MB");
        }
        long currentTimeMillis = System.currentTimeMillis();
        String currentDay = simpleDateFormat.format(currentTimeMillis);
//        String currentDay = simpleDateFormat.format(new Date());
        log.info("current day == > " + currentDay);
        String dayPath = imagePath + File.separator + currentDay;
        File dayPathFile = new File(dayPath);
        if (!dayPathFile.exists()) {
            dayPathFile.mkdirs();
        }
        String targetName = String.valueOf(idWorker.nextId());
        // 根据我们定的规则进行命名
        String targetPath = dayPath + File.separator +
                type + File.separator + targetName + "." + type;
        File targetFile = new File(targetPath);
        // File targetFile = new File(imagePath + File.separator + originalFilename);
        log.info("targetFile == > " + targetFile);
        if (!targetFile.getParentFile().exists()) {
            targetFile.mkdirs();
        }
        try {
            if (!targetFile.exists()) {
                targetFile.createNewFile();
            }
            // 保存文件
            file.transferTo(targetFile);
            // TODO
            // 返回结果:包含这个图片的名称和访问路径
            // 第一个是访问路径 -- > 得对应着解析来
            HashMap<String, String> result = new HashMap<>();
            String resultPath = currentTimeMillis + "_" + targetName + "." + type;
//            result.put("path", resultPath);
            result.put("id", resultPath);
            // 第二个是名称 ---> alt="图片描述",如果不写，前端可以使用名称作为这个描述
            result.put("name", originalFilename);
            Images images = new Images();
            images.setContentType(contentType);
            images.setId(targetName);
            images.setCreateTime(new Date());
            images.setUpdateTime(new Date());
            images.setPath(targetFile.getPath());
            images.setName(originalFilename);
            images.setUrl(resultPath);
            images.setState("1");
            SobUser sobUser = iUserService.checkSobUser();
            images.setUserId(sobUser.getId());
            // 记录文件
            // 保存记录到数据里
            imagesDao.save(images);
            // TODO
            // 返回结果
            return ResponseResult.SUCCESS("文件上传成功").setData(result);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ResponseResult.FAILED("图片上传失败，稍后重试");
    }

    private String getString(String contentType, String originalFilename) {
        String type = null;
        if (Constants.ImagesType.TYPE_PNG_WITH_PREFIX.equals(contentType)
                && originalFilename.endsWith(Constants.ImagesType.TYPE_PNG)) {
            type = Constants.ImagesType.TYPE_PNG;
        } else if (Constants.ImagesType.TYPE_GIF_WITH_PREFIX.equals(contentType)
                && originalFilename.endsWith(Constants.ImagesType.TYPE_GIF)) {
            type = Constants.ImagesType.TYPE_GIF;
        } else if (Constants.ImagesType.TYPE_JPG_WITH_PREFIX.equals(contentType)
                && originalFilename.endsWith(Constants.ImagesType.TYPE_JPG)) {
            type = Constants.ImagesType.TYPE_JPG;
        }
        return type;
    }

    /**
     * 读取照片
     *
     * @param response
     * @param imageId
     * @throws IOException
     */
    @Override
    public void viewImage(HttpServletResponse response, String imageId) throws IOException {
        // 配置的目录已知
        // 根据尺寸来动态返回图片给前端
        // 好处:减少带宽占用，传输速度快
        // 缺点:消耗后台的CPU资源
        // 推荐做法:上传上来的时候，把图片复制成三个尺寸:大，中，小
        // 根据尺寸范围,返回结果即可
        // 需要日期
        String[] paths = imageId.split("_");
        String dayValue = paths[0];
        String format = simpleDateFormat.format(Long.valueOf(dayValue));
        log.info("viewImage  format == > " + format);
        String name = paths[1];
        String type = name.substring(name.length() - 3);
//        File file = new File(imagePath + File.separator + "shu.png");
        String targetPath = imagePath + File.separator + format + File.separator +
                type + File.separator + name;
        log.info("get image target path === > " + targetPath);
        File file = new File(targetPath);
        OutputStream writer = null;
        FileInputStream fos = null;
        try {
            response.setContentType("image/png");
            writer = response.getOutputStream();
            // 读取
            fos = new FileInputStream(file);
            byte[] buff = new byte[1024];
            int len;
            while (((len = fos.read(buff)) != -1)) {
                writer.write(buff, 0, len);
            }
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                fos.close();
            }
            if (writer != null) {
                writer.close();
            }
        }
    }

    /**
     * 获取图片列表
     *
     * @param page
     * @param size
     * @return
     */
    @Override
    public ResponseResult listImages(int page, int size) {
        //处理page,size
        page = this.checkPage(page);
        size = this.checkSize(size);
        SobUser sobUser = iUserService.checkSobUser();
        if (sobUser == null) {
            return ResponseResult.ACCOUNT_NOT_LOGIN();
        }
        //创建分页条件
        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        //查询
        Pageable pageable = PageRequest.of(page - 1, size, sort);
        //返回结果
        final String userId = sobUser.getId();
        Page<Images> all = imagesDao.findAll(new Specification<Images>() {
            @Override
            public Predicate toPredicate(Root<Images> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) {
                //根据用户ID (视频里没有，笔记里有)
                Predicate userIdPre = cb.equal(root.get("userId").as(String.class), userId);
                //根据状态
                Predicate statePre = cb.equal(root.get("state").as(String.class), "1");
                return cb.and(userIdPre,statePre);
            }
        }, pageable);
        return ResponseResult.SUCCESS("获取图片列表成功.").setData(all);
    }

    /**
     * 删除图片，
     * 只改变状态
     *
     * @param imageId
     * @return
     */
    @Override
    public ResponseResult deleteById(String imageId) {
        int result = imagesDao.deleteImagesByUpdateState(imageId);
        if (result>0) {
            return ResponseResult.SUCCESS("删除成功.");
        }
        return ResponseResult.FAILED("图片不存在.");
    }
}
